//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<make_type.h>
///	@path	~/src/lib/utilities/
///	@date	2008/11/09
///	@desc	Make types from a type sequence.

#pragma once

#include <boost/mpl/vector.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/void.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/find.hpp>

namespace xeres {

	/*! 
		\class	make_type
		\brief	Make a mixed type from an mpl sequence.
	*/
	template<
		typename _Types , // Type sequence.
		typename _Holder = void // Type holder wrap for intrusive operation.
	> struct make_type
	{
		typedef boost::mpl::void_ void_;
 		typedef _Types types;
		typedef typename boost::mpl::begin<types>::type first;
		typedef typename boost::mpl::end<types>::type last;

		// Make holder for field.
		template<typename H> struct make_holder_helper {
			template<typename T, typename N> struct type : public H::type<T,N> {};
		};
		template<> struct make_holder_helper<void> {
			template<typename T, typename N> struct type : public T {};
		};

		typedef make_holder_helper<_Holder> _RealHolder;

		// Make real holder
		template< typename T , typename next_type > struct make_holder {
			typedef typename _RealHolder::type<T,next_type> type;
		};

		template<typename T , typename next_type> struct holder : public next_type , make_holder< T, typename next_type >::type {
			typedef T entity;
			typedef next_type next_t;
			typedef typename make_holder< T, typename next_type >::type holder_t;
			typedef typename boost::mpl::push_back<
				typename next_type::holder_seq , holder_t
			>::type holder_seq;

			holder_t * next_holder( void ) {
				return static_cast<holder_t*>(this);
			}
		};
		template<typename next_type> struct holder<void_,next_type> : public next_type {
			typedef void_ entity;
			typedef next_type next_t;
			typedef typename next_type::holder_seq holder_seq;
			void * next_holder( void ) {
				return NULL;
			}
		};
		template<typename T> struct holder<T,void> : public make_holder< T,void >::type {
			typedef T entity;
			typedef holder<T,void> last_t;
			typedef typename make_holder< T,void >::type holder_t;
			typedef boost::mpl::vector< holder_t > holder_seq;

			holder_t * next_holder( void ) {
				return static_cast<holder_t*>(this);
			}
		};

		template< typename it , typename next_type > struct make
		{
			typedef typename make<
				typename boost::mpl::next<it>::type ,
				holder< typename boost::mpl::deref<it>::type , next_type >
			>::type type;
		};

		template<typename next_type> struct make< last , next_type >
		{
			typedef holder< typename boost::mpl::deref<last>::type , next_type > type;
		};

		// From first type begins.
		typedef typename make<first , void>::type core_type;
		typedef typename core_type::holder_seq holder_types;

		typedef struct _type : public core_type
		{
			typedef typename types field_types;
			typedef typename core_type::holder_seq holder_types;

			template<int index> struct type_at
			{
				typedef typename make< boost::mpl::advance< first, boost::mpl::int_<index> > , void_ > type;
			};

			template<int i> struct holder_at
			{
				typedef typename boost::mpl::at_c<holder_types,i>::type type;
			};

			template<int i> struct field_at
			{
				typedef typename boost::mpl::at_c<field_types,i>::type type;
			};

			template<typename T> struct find_holder
			{
				typedef typename boost::mpl::find<holder_types,T>::type type;
			};

			template<typename T> struct find_field
			{
				typedef typename boost::mpl::find<field_types,T>::type type;
			};

			// Get holder.
			template<int i> typename holder_at<i>::type& __holder__( void )
			{
				return *static_cast<typename holder_at<i>::type*>(this);
			}
			template<int i> typename const holder_at<i>::type& __holder__( void ) const
			{
				return *static_cast<const typename holder_at<i>::type*>(this);
			}

			// Get field.
			template<int i> typename field_at<i>::type& __field__( void )
			{
				return static_cast<typename field_at<i>::type&>(__holder__<i>());
			}
			template<int i> typename const field_at<i>::type& __field__( void ) const
			{
				return static_cast<typename const field_at<i>::type&>(__holder__<i>());
			}

			// Find holder.
			template<typename T> typename boost::mpl::deref<typename find_field<T>::type>::type& __find__( void )
			{
				return *static_cast<typename boost::mpl::deref<typename find_field<T>::type>::type*>(this);
			}

			// Forward mpl's for_each.
			template<
				typename Sequence ,
				typename TransformOp ,
				typename F
			> void for_each(F f,Sequence* = 0,TransformOp* = 0)
			{
				boost::mpl::for_each(f,(Sequence*)0,(TransformOp*)0);
			}

			template<
				typename Sequence , typename F
			> void for_each(F f, Sequence* = 0)
			{
				boost::mpl::for_each(f,(Sequence*)0);
			}

		} type;
	};

#define	MAKE_TYPE( ... )			make_type< boost::mpl::vector< __VA_ARGS__ > >::type
	
} // namespace xeres
